#include <iostream>
#include <sstream>
#include <fstream>
#include "inp.h"
#include "declaration.h"
// #include "flow.h"
// using namespace inp;
using namespace std;

/**
 * @brief 回显用户的输入
 * 
 */
void confirm() noexcept
{
    // using namespace inp;
    cout << "p01 = " << inp::p01 << "\n"
         << "t01 = " << inp::t01 << "\n"
         << "p2 = " << inp::p2 << "\n"
         << "gamma = " << inp::gamma << "\n"
         << "cpgas = " << inp::cpgas << "\n"
         << "cfl = " << inp::cfl << "\n"
         << "epsirs = " << inp::epsirs << "\n";

    if (inp::kdissip == "c" || inp::kdissip == "C")
        cout << "vis2 = " << inp::vis2 << "\n"
             << "vis4 = " << inp::vis4 << "\n";
    else if (inp::kdissip == "r" || inp::kdissip == "R")
        cout << "iorder = " << inp::iorder << "\n"
             << "limfac = " << inp::limfac << "\n"
             << "epsentr = " << inp::epsentr << "\n";
}

void OutPut(const flow& result, const Grid& grid) noexcept
{
    // using namespace inp;
    ofstream solution{inp::fnplot, ios_base::out};
    if(!solution) 
    {
        cerr << "open solution file err\n";
        exit(EXIT_FAILURE);
    }
    solution << "TITLE = \" visualization of the flow\" \n" 
        << "VARIABLES = \"x\", \"area\", \"rho\", \"u\", \"p\", \"T\", \"Mach\", \"mass flow\" \n";
    
    double rho, u, temp, c, mach;
    const vec1d<double>& p = result.p;
    const vec2d<double>& cv = result.cv;
    const vec1d<double>& area = grid.area;
    const vec1d<double>& x = grid.x;
    const size_t ib2 = grid.ib2;

    for(size_t i = 1; i < ib2; ++i)
    {
        rho = cv(i, 0) / area(i);
        u = cv(i, 1) / cv(i, 0);
        temp = p(i)/(rho*inp::rgas);
        c = sqrt(inp::gamma * p(i)/ rho);
        mach = u/c;

        solution << scientific << setprecision(9)
        << x(i) << "\t" << area(i) << "\t" 
        << rho << "\t" << u << "\t"
        << p(i) << "\t" << temp << "\t"
        << mach << "\t" << cv(i, 1) << "\n";
    }
    solution.close();
}

// 下面的源码级重用性很差
/**
cl_context CreateContext(cl_device_type device_type)
{
    cl_int err;
    cl_uint num_platform = 0;
    err = clGetPlatformIDs(0, NULL, &num_platform);
    assert((err == CL_SUCCESS) && (0 < num_platform));
    cl_platform_id *platform_idp{new cl_platform_id[num_platform]};
    err = clGetPlatformIDs(num_platform, platform_idp, NULL);
    assert(err == CL_SUCCESS);

    cl_context context;
    for (cl_uint i = 0; i < num_platform; ++i)
    {
        cl_context_properties properties[] = {
            CL_CONTEXT_PLATFORM,
            (cl_context_properties)platform_idp[i],
            0};

        context = clCreateContextFromType(properties, device_type, NULL, NULL, &err);
        if (err == CL_SUCCESS)
            break;
    }
    if (err == CL_SUCCESS)
        return context;
    else
    {
        cout << "create context fail\n";
        exit(EXIT_FAILURE);
    }
}

cl_command_queue CreateCommandQueue(cl_context context, cl_device_id *device_p)
{
    cl_int err;
    size_t device_buffer_size;
    err = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &device_buffer_size);
    assert(err == CL_SUCCESS);
    cl_device_id *device_idp{new cl_device_id[device_buffer_size / sizeof(cl_device_id)]};
    err = clGetContextInfo(context, CL_CONTEXT_DEVICES, device_buffer_size, device_idp, NULL);
    assert(err == CL_SUCCESS);

    cl_queue_properties properties[] = {CL_QUEUE_PROPERTIES, CL_QUEUE_PROFILING_ENABLE, 0};
    // 使用上下文关联的设备中的第一个
    cl_command_queue command_queue =
        clCreateCommandQueueWithProperties(context, device_idp[0], properties, &err);
    assert(err == CL_SUCCESS);

    *device_p = device_idp[0];
    delete[] device_idp;
    return command_queue;
}

cl_program CreateProgram(cl_context context, cl_device_id device_id, const char *file_name)
{
    cl_int err;
    ifstream clfile{file_name, ios_base::in};
    if (!clfile)
    {
        cerr << "open file error: " << file_name << "\n";
        exit(EXIT_FAILURE);
    }
    ostringstream oss;
    oss << clfile.rdbuf();
    string src{oss.str()};
    // 得到内核文件源代码
    const char *srcStr{src.c_str()};

    cl_program program = clCreateProgramWithSource(context, 1, (const char **)&srcStr, NULL, &err);
    assert(err == CL_SUCCESS);

    string options{};
    err = clBuildProgram(program, 1, &device_id, (const char *)options.c_str(), NULL, NULL);
    if (err != CL_SUCCESS)
    {
        // 输出编译错误信息
        size_t log_size;
        err = clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
        assert(err == CL_SUCCESS);

        char* err_log = new char[log_size+1];
        err = clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, log_size, err_log, NULL);
        assert(err == CL_SUCCESS);
        err_log[log_size] = '\0';
        cerr << "build program fail\n";
        cerr << err_log;
        clReleaseProgram(program);
        delete [] err_log;
        exit(EXIT_FAILURE);
    }
    return program;
}

std::pair<cl_kernel*, int> CreateKernel(cl_program program)
{
    
}
**/